#include <unistd.h>
#include <stdio.h>
#include "MIServiceConnector.h"
#include "MIEvent.h"

PoliceThread::PoliceThread(MIServiceConnector* r)
 : auxiliary::Thread()
{
	ref = r;
}

void PoliceThread::run()
{
	unsigned int i;
	collaboration::ListOfUserNames* lu;
	while(true)
	{
		lu = ref->mi_client->get_data_accessor()->non_updated_users(ref->application);
												
		for (i=0; i<lu->length(); i++)
		{
			ref->mi_client->get_data_accessor()->disconnect_user(ref->application, (*lu)[i]);
			
			MIEvent* evento = new MIEvent();
			evento->member_value("mi_type", (PortableInteger)DISCONNECT);
			evento->member_value("application", ref->application);
			evento->member_value("user", (char*)(*lu)[i]);

			ref->handler->push(evento);

			delete evento;
		}
		
		sleep(60);
	}
}

KeepAliveThread::KeepAliveThread(MIServiceConnector* r)
 : auxiliary::Thread()
{
	ref = r;
}

void KeepAliveThread::run()
{
	while(true)
	{
		if (ref->connected)
		{
			ref->mi_client->get_data_accessor()->update_user_time(ref->application, ref->user);
			sleep(10);
		}
		else
		{
			sleep(20);
		}
	}
}

MIServiceConnector::MIServiceConnector(const char* app, const char* u, const char* pass, 
										EventHandler* h, MI_client* mc) 
										: ListeningObject()
{
	user = CORBA::string_dup(u);
	password = CORBA::string_dup(pass);
	application = CORBA::string_dup(app);
	role = NULL;
	handler = h;
	mi_client = mc;
	login_allowed = false;
	connected = false;
	keep_alive_thread = new KeepAliveThread(this);
	police_thread = new PoliceThread(this);
	
	police_thread->start(); //inicia la hebra policia
}

MIServiceConnector::~MIServiceConnector()
{
	CORBA::string_free(user);
	CORBA::string_free(password);
	CORBA::string_free(application);
	
	if (role != NULL) CORBA::string_free(role);
	
	delete keep_alive_thread;
	delete police_thread;
}

collaboration::MIConnection* MIServiceConnector::login()
{	
	collaboration::MIConnection* con = mi_client->get_data_accessor()->login(application, user, password);
	if (strcmp(con->error_message, "") == 0) login_allowed = true;
	else login_allowed = false;
	return con;
}

bool MIServiceConnector::admin()
{
	return mi_client->get_data_accessor()->user_info(application, user)->is_admin;
}

char* MIServiceConnector::connect_user()
{
	if (login_allowed)
	{
		if (role != NULL) CORBA::string_free(role);
		role = CORBA::string_dup(mi_client->get_data_accessor()->connect_user(application, user));
	
		//se distribuye el evento de login si no hubo error
		if (role != NULL)
		{
			MIEvent* evento = new MIEvent();
			evento->member_value("mi_type", (PortableInteger)LOGIN);
			evento->member_value("application", application);
			evento->member_value("user", user);
			evento->member_value("role", role);
		
			handler->push(evento);
			
			keep_alive_thread->start(); //se inicia la hebra keep_alive
			
			delete evento;
		}
		
		connected = true;
	
		return role;
	}
	else return NULL;
}

void MIServiceConnector::disconnect_user()
{
	if (connected)
	{
		connected = false;
		role = NULL;
		login_allowed = false;
		
		mi_client->get_data_accessor()->disconnect_user(application, user);
		
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)DISCONNECT);
		evento->member_value("application", application);
		evento->member_value("user", user);

		handler->push(evento);
		
		delete evento;
		
		keep_alive_thread->cancel();
	}
}

collaboration::MIConnection* MIServiceConnector::change_connected_user_role(const char* newrole)
{
	collaboration::MIConnection* con = mi_client->get_data_accessor()->
										change_connected_user_role(application, user, newrole);
	
	//distribuir el evento en caso de no haber error
	if (strcmp(con->error_message, "") == 0)
	{
		if (role != NULL) CORBA::string_free(role);
		role = CORBA::string_dup(newrole);
		
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)USER_ROLE_CHANGED);
		evento->member_value("application", application);
		evento->member_value("user", user);
		evento->member_value("role", role);

		handler->push(evento);
		
		delete evento;
	}
	
	return con;
}

collaboration::ListOfUserNames* MIServiceConnector::role_users(const char* role_name)
{
	return mi_client->get_data_accessor()->role_users(application, role_name);
}

collaboration::ListOfUserNames* MIServiceConnector::role_users()
{
	return mi_client->get_data_accessor()->role_users(application, role);
}

collaboration::ListOfUsers* MIServiceConnector::users_info()
{
	return mi_client->get_data_accessor()->users_info(application);
}

collaboration::ListOfRoles* MIServiceConnector::roles_info()
{
	return mi_client->get_data_accessor()->roles_info(application);
}

collaboration::MIUser* MIServiceConnector::user_info()
{
	return mi_client->get_data_accessor()->user_info(application, user);
}

collaboration::MIUser* MIServiceConnector::user_info(const char* user_name)
{
	return mi_client->get_data_accessor()->user_info(application, user_name);
}

collaboration::MIRole* MIServiceConnector::role_info()
{
	return mi_client->get_data_accessor()->role_info(application, role);
}

collaboration::MIRole* MIServiceConnector::role_info(const char* role_name)
{
	return mi_client->get_data_accessor()->role_info(application, role_name);
}

collaboration::ListOfUsers* MIServiceConnector::connected_users()
{
	return mi_client->get_data_accessor()->connected_users_info(application);
}

collaboration::ListOfComponentNames* MIServiceConnector::components()
{
	return mi_client->get_data_accessor()->application_components(application);
}

collaboration::ListOfRoles* MIServiceConnector::allowed_roles()
{
	return mi_client->get_data_accessor()->allowed_roles(application, user);
}

collaboration::ListOfRoles* MIServiceConnector::allowed_roles(const char* user_name)
{
	return mi_client->get_data_accessor()->allowed_roles(application, user_name);
}

bool MIServiceConnector::set_user_component_permissions(const char* user_name, const char* comp, int level)
{
	CORBA::Boolean correcto = mi_client->get_data_accessor()->
									set_user_component_permissions(application, user_name, comp, level);
									
	if (correcto) //distribuir evento
	{
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)USER_COMPONENT_PERMISSIONS_CHANGE);
		evento->member_value("application", application);
		evento->member_value("user", user_name);
		evento->member_value("component", comp);

		handler->push(evento);
		
		delete evento;
	}
	
	return correcto;
}

bool MIServiceConnector::set_user_component_permissions(const char* comp, int level)
{
	CORBA::Boolean correcto = mi_client->get_data_accessor()->
									set_user_component_permissions(application, user, comp, level);
									
	if (correcto) //distribuir evento
	{
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)USER_COMPONENT_PERMISSIONS_CHANGE);
		evento->member_value("application", application);
		evento->member_value("user", user);
		evento->member_value("component", comp);

		handler->push(evento);
		
		delete evento;
	}
	
	return correcto;
}

bool MIServiceConnector::set_role_component_permissions(const char* role_name, const char* comp, int level)
{
	CORBA::Boolean correcto = mi_client->get_data_accessor()->
									set_role_component_permissions(application, role_name, comp, level);
									
	if (correcto) //distribuir evento
	{
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)ROLE_COMPONENT_PERMISSIONS_CHANGE);
		evento->member_value("application", application);
		evento->member_value("role", role_name);
		evento->member_value("component", comp);

		handler->push(evento);
		
		delete evento;
	}
	
	return correcto;
}

bool MIServiceConnector::set_role_component_permissions(const char* comp, int level)
{
	if (role != NULL)
	{
		CORBA::Boolean correcto = mi_client->get_data_accessor()->
										set_role_component_permissions(application, role, comp, level);
									
		if (correcto) //distribuir evento
		{
			MIEvent* evento = new MIEvent();
			evento->member_value("mi_type", (PortableInteger)ROLE_COMPONENT_PERMISSIONS_CHANGE);
			evento->member_value("application", application);
			evento->member_value("role", role);
			evento->member_value("component", comp);

			handler->push(evento);
			
			delete evento;
		}
	
		return correcto;	
	}
	else return false;
}

PortableInteger MIServiceConnector::get_user_component_permissions(const char* comp)
{
	return mi_client->get_data_accessor()->get_user_component_permissions(application, user, comp);
}

PortableInteger MIServiceConnector::get_user_component_permissions(const char* user_name, const char* comp)
{
	return mi_client->get_data_accessor()->get_user_component_permissions(application, user_name, comp);
}	

PortableInteger MIServiceConnector::get_role_component_permissions(const char* comp)
{
	return mi_client->get_data_accessor()->get_role_component_permissions(application, role, comp);
}

PortableInteger MIServiceConnector::get_role_component_permissions(const char* role_name, const char* comp)
{
	return mi_client->get_data_accessor()->get_role_component_permissions(application, role_name, comp);
}

bool MIServiceConnector::new_user(const char* user_name, const char* pass, 
						const char* default_role, bool is_admin)
{
	CORBA::Boolean correcto = mi_client->get_data_accessor()->
									new_user(application, user_name, pass, default_role, is_admin);
								
	if (correcto) //distribuir evento
	{
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)NEW_USER);
		evento->member_value("application", application);
		evento->member_value("user", user_name);

		handler->push(evento);
		
		delete evento;
	}

	return correcto;		
}

bool MIServiceConnector::new_role(const char* role_name)
{
	CORBA::Boolean correcto = mi_client->get_data_accessor()->new_role(application, role_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)NEW_ROLE);
		evento->member_value("application", application);
		evento->member_value("role", role_name);

		handler->push(evento);
		
		delete evento;
	}

	return correcto;
}

bool MIServiceConnector::new_user_allowed_role(const char* user_name, const char* role_name)
{
	CORBA::Boolean correcto = mi_client->get_data_accessor()->
								new_user_allowed_role(application, user_name, role_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)NEW_ALLOWED_ROLE);
		evento->member_value("application", application);
		evento->member_value("user", user_name);
		evento->member_value("role", role_name);

		handler->push(evento);
		
		delete evento;
	}

	return correcto;
}

bool MIServiceConnector::new_user_allowed_role(const char* role_name)
{
	CORBA::Boolean correcto = mi_client->get_data_accessor()->
								new_user_allowed_role(application, user, role_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)NEW_ALLOWED_ROLE);
		evento->member_value("application", application);
		evento->member_value("user", user);
		evento->member_value("role", role_name);

		handler->push(evento);
		
		delete evento;
	}

	return correcto;
}

bool MIServiceConnector::remove_allowed_user_role(const char* user_name, const char* role_name)
{
	CORBA::Boolean correcto = mi_client->get_data_accessor()->
								remove_allowed_user_role(application, user_name, role_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)REMOVE_ALLOWED_ROLE);
		evento->member_value("application", application);
		evento->member_value("user", user_name);
		evento->member_value("role", role_name);

		handler->push(evento);
		
		delete evento;
	}

	return correcto;
}

bool MIServiceConnector::remove_allowed_user_role(const char* role_name)
{
	CORBA::Boolean correcto = mi_client->get_data_accessor()->
								remove_allowed_user_role(application, user, role_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)REMOVE_ALLOWED_ROLE);
		evento->member_value("application", application);
		evento->member_value("user", user);
		evento->member_value("role", role_name);

		handler->push(evento);
		
		delete evento;
	}

	return correcto;
}

bool MIServiceConnector::remove_user(const char* user_name)
{
	CORBA::Boolean correcto = mi_client->get_data_accessor()->remove_user(application, user_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)REMOVE_USER);
		evento->member_value("application", application);
		evento->member_value("user", user_name);

		handler->push(evento);
		
		delete evento;
	}

	return correcto;
}

bool MIServiceConnector::remove_role(const char* role_name)
{
	CORBA::Boolean correcto = mi_client->get_data_accessor()->remove_role(application, role_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent* evento = new MIEvent();
		evento->member_value("mi_type", (PortableInteger)REMOVE_ROLE);
		evento->member_value("application", application);
		evento->member_value("role", role_name);

		handler->push(evento);
		
		delete evento;
	}

	return correcto;
}

char* MIServiceConnector::user_actual_role(const char* user_name)
{
	return mi_client->get_data_accessor()->user_actual_role(application, user_name);
}

char* MIServiceConnector::user_actual_role()
{
	return role;
}

void MIServiceConnector::commit()
{
	mi_client->get_data_accessor()->commit();
}
